package com.bea.ftd.mapping.service.impl;

import com.bea.ftd.common.dao.MsgInConfRepo;
import com.bea.ftd.common.dao.MsgMappingRepo;
import com.bea.ftd.common.dao.MsgOutConfRepo;
import com.bea.ftd.common.dao.SignInfoRepo;
import com.bea.ftd.common.entity.MsgInConf;
import com.bea.ftd.common.entity.MsgMapping;
import com.bea.ftd.common.entity.MsgOutConf;
import com.bea.ftd.common.entity.SignInfo;
import com.bea.ftd.mapping.service.TransMsgService;
import com.bea.ftd.common.utils.XmlUtils;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

@Service
public class TransMsgServiceImpl implements TransMsgService {

    @Autowired
    private MsgInConfRepo msgInConfRepo;

    @Autowired
    private MsgMappingRepo msgMappingRepo;

    @Autowired
    private MsgOutConfRepo msgOutConfRepo;

    @Autowired
    private SignInfoRepo signInfoRepo;

    @Override
    @Cacheable(value = "MsgInConf")
    public List<MsgInConf> findAllMsgInConf(String apiId) {
        List<MsgInConf> msgIns = msgInConfRepo.findAllByApiId(apiId);
        return msgIns;
    }

    @Override
    @Cacheable(value = "MsgMapping")
    public List<MsgMapping> findAllMapping(String apiId) {
        List<MsgMapping> msgs = msgMappingRepo.findAllByInterfaceId(apiId);
        return msgs;
    }

    @Override
    @Cacheable(value = "MsgOutConf")
    public List<MsgOutConf> findAllMsgOutConf(String apiId) {
        List<MsgOutConf> MsgOuts = msgOutConfRepo.findAllByApiId(apiId);
        return MsgOuts;
    }

    @Override
    public Map<String, Object> collectMapTrans(Map<String, Object> mapIn,List<MsgInConf> msgInConfs, List<MsgMapping> msgs, List<MsgOutConf> msgOutConfs) {


        Map<String,Object> res = new HashMap<String,Object>();
        List<List<String>> msgOutlinkNodes = getMsgOutLinkNodes(msgOutConfs);
        //返回输出Map数据节点，包含各个节点key值，不包含value

        List<List<String>> msgInLinkNodes = getMsgInLinkNodes(msgInConfs);
        List<String> msgInKeyList = new ArrayList();
        for(List<String> msgInLinkNode : msgInLinkNodes){
            msgInKeyList.add(msgInLinkNode.get(msgInLinkNode.size()-1));
        }
        int index =0;
        int rootIndex = 0;
        Map<String,Object> inValue = new LinkedHashMap<>();
        for(MsgMapping msgMapping:msgs){

            int i=0,j=0;
            for(MsgInConf msgInConf:msgInConfs){
                if(msgInConf.getParamName().equals(msgMapping.getInMsgParamName())){
                    break;
                }
                i++;
            }

            for(MsgOutConf msgOutConf:msgOutConfs){
                if(msgOutConf.getParamName().equals(msgMapping.getOutMsgParamName())){
                    break;
                }
                j++;
            }

            //获得输入根节点
            if(index == 0){
                Map<String,Object> tempValue = mapIn;

                for(String msgInLinkNode:msgInLinkNodes.get(i)){
                    tempValue = (Map<String,Object>)tempValue.get(msgInLinkNode);
                }
                int size = msgInLinkNodes.get(i).size();
                inValue.put(msgInLinkNodes.get(i).get(size-1),tempValue);

                rootIndex = msgInLinkNodes.get(i).size() -1;
                break;
            }
            index++;
        }

        stepMapDataStruct(inValue,msgInKeyList,msgs);

        return inValue;
    }

    private Map<String,Object> stepMapDataStruct(Map<String,Object> mapIn,List<String> msgInKeyList,List<MsgMapping> msgs){
        Iterator<Map.Entry<String,Object>> entries = mapIn.entrySet().iterator();
        while (entries.hasNext()){
            Map.Entry<String, Object> entrie = entries.next();
            String key = entrie.getKey();
            Object value = entrie.getValue();
            System.out.println("key="+key+":value="+value.toString());
            if(value instanceof java.util.Map){
                stepMapDataStruct((Map<String,Object>)value,msgInKeyList,msgs);
            }
            if(checkKey(key,msgInKeyList)){
                for(MsgMapping msgMapping:msgs){
                    if(msgMapping.getInMsgParamName().equals(key)){
                        entrie.getKey().replace(key,msgMapping.getOutMsgParamName());
                    }
                }

            }else{
                entries.remove();
            }
        }

        return mapIn;
    }

    private boolean checkKey(String key,List<String> msgInKeyList){
        if(msgInKeyList.contains(key)){
            return true;
        }else {
            return false;
        }
    }

    private List<List<String>> getMsgInLinkNodes(List<MsgInConf> msgInConfs){
        List<List<String>> linkNodes =null;
        for(MsgInConf msgInConf:msgInConfs){
            if(msgInConf.getParentNode().equals("")){
                linkNodes = new ArrayList<>();
                List<String> root = new ArrayList<>();
                root.add(msgInConf.getParamName());
                linkNodes.add(root);
                break;
            }
        }
        if(linkNodes != null ){
            for(MsgInConf msgIn:msgInConfs){
                List<String >otherLinkNode = null;
                for(List<String> oneLindNodes:linkNodes){
                    if(oneLindNodes.get(oneLindNodes.size()-1).equals(msgIn.getParentNode())){
                        otherLinkNode = (ArrayList<String>)((ArrayList<String>) oneLindNodes).clone();
                        otherLinkNode.add(msgIn.getParamName());
                        continue;
                    }
                }
                if(otherLinkNode!=null){
                    linkNodes.add(otherLinkNode);
                }
            }
        }
        return linkNodes;
    }

    private List<List<String>> getMsgOutLinkNodes(List<MsgOutConf> msgOutConfs){
        List<List<String>> linkNodes =null;
        for(MsgOutConf msgOutConf:msgOutConfs){
            if(msgOutConf.getParentNode().equals("")){
                linkNodes = new ArrayList<>();
                List<String> root = new ArrayList<>();
                root.add(msgOutConf.getParamName());
                linkNodes.add(root);
                break;
            }
        }
        if(linkNodes != null ){
            for(MsgOutConf msgIn:msgOutConfs){
                List<String >otherLinkNode = null;
                for(List<String> oneLindNodes:linkNodes){
                    if(oneLindNodes.get(oneLindNodes.size()-1).equals(msgIn.getParentNode())){
                        otherLinkNode = (ArrayList<String>)((ArrayList<String>) oneLindNodes).clone();
                        otherLinkNode.add(msgIn.getParamName());
                        continue;
                    }
                }
                if(otherLinkNode!=null){
                    linkNodes.add(otherLinkNode);
                }
            }
        }
        return linkNodes;
    }


    @Override
    public String mapOutToData(Map<String, Object> mapOut, String msgOutType, String apiId) throws IOException {
        String dataOut = null;
        List<MsgInConf> msgInConfs = findAllMsgInConf(apiId);
        List<MsgMapping> msgMappings = findAllMapping(apiId);
        List<MsgOutConf> msgOutConfs = findAllMsgOutConf(apiId);
        if(msgOutConfs.size()==0||msgMappings.size()==0){
            return dataOut;
        }

        if ("JSON".equalsIgnoreCase(msgOutType)){
            Map<String, Object> resMap = collectMapTrans(mapOut,findAllMsgInConf(apiId),findAllMapping(apiId),findAllMsgOutConf(apiId));
            if (resMap.size()!=0){
                JSONObject jsonObject = JSONObject.fromObject(resMap);
                dataOut = jsonObject.toString();
            }else{
                dataOut = null;
            }
        }
        if("XML".equalsIgnoreCase(msgOutType)){

            Map<String, Object> resMap = collectMapTrans(mapOut,findAllMsgInConf(apiId),findAllMapping(apiId),findAllMsgOutConf(apiId));
            if (resMap.size()!=0){
                dataOut = XmlUtils.map2Xmlstring(resMap);
            }else{
                dataOut = null;
            }
        }
        return dataOut;
    }

    @Override
    @Cacheable(value = "SignInfo")
    public SignInfo encryptType(String partnerCode) {
        SignInfo signInfo = this.signInfoRepo.findByPartnerCode(partnerCode);
        return signInfo;
    }

}
